/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "plugins/ecmascript/runtime/base/builtins_base.h"

#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h"
#include "plugins/ecmascript/runtime/ecma_string.h"
#include "plugins/ecmascript/runtime/ecma_vm.h"
#include "plugins/ecmascript/runtime/global_env.h"
#include "plugins/ecmascript/runtime/js_array.h"
#include "plugins/ecmascript/runtime/js_function.h"
#include "plugins/ecmascript/runtime/js_object-inl.h"

#include "plugins/ecmascript/runtime/object_factory.h"
#include "plugins/ecmascript/runtime/tagged_array-inl.h"
#include "plugins/ecmascript/tests/runtime/common/test_helper.h"

// NOLINTNEXTLINE(google-build-using-namespace)
using namespace ark::ecmascript;
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace ark::ecmascript::builtins;

// NOLINTBEGIN(readability-magic-numbers)

namespace ark::test {
class BuiltinsFunctionTest : public testing::Test {
public:
    static void SetUpTestCase()
    {
        GTEST_LOG_(INFO) << "SetUpTestCase";
    }

    static void TearDownTestCase()
    {
        GTEST_LOG_(INFO) << "TearDownCase";
    }

    void SetUp() override
    {
        TestHelper::CreateEcmaVMWithScope(instance_, thread_, scope_);
    }

    void TearDown() override
    {
        TestHelper::DestroyEcmaVMWithScope(instance_, scope_);
    }

protected:
    // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
    JSThread *thread_ {nullptr};

private:
    PandaVM *instance_ {nullptr};
    EcmaHandleScope *scope_ {nullptr};
};

// native function for test apply and call
JSTaggedValue TestFunctionApplyAndCall(EcmaRuntimeCallInfo *argv)
{
    JSThread *thread = argv->GetThread();
    [[maybe_unused]] EcmaHandleScope handleScope(thread);
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();

    int result = 0;
    for (uint32_t index = 0; index < argv->GetArgsNumber(); ++index) {
        result += builtins_common::GetCallArg(argv, index)->GetInt();
    }
    JSHandle<JSTaggedValue> thisValue(builtins_common::GetThis(argv));

    JSTaggedValue testA =
        JSObject::GetProperty(thread, thisValue,
                              JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")))
            .GetValue()
            .GetTaggedValue();
    JSTaggedValue testB =
        JSObject::GetProperty(thread, thisValue,
                              JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")))
            .GetValue()
            .GetTaggedValue();

    result = result + testA.GetInt() + testB.GetInt();
    return builtins_common::GetTaggedInt(result);
}

// func.apply(thisArg)
TEST_F(BuiltinsFunctionTest, FunctionPrototypeApply)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
    // ecma 19.2.3.1: func
    JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));

    // ecma 19.2.3.1: thisArg
    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(1)));
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(2)));

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(func.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Apply(ecmaRuntimeCallInfo.get());

    ASSERT_EQ(result.GetRawData(), JSTaggedValue(3).GetRawData());

    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")));
    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")));
}

// func.apply(thisArg, argArray)
TEST_F(BuiltinsFunctionTest, FunctionPrototypeApply1)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    // ecma 19.2.3.1: func
    JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));

    // ecma 19.2.3.1: thisArg
    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(10)));
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(20)));

    // ecma 19.2.3.1: argArray
    JSHandle<JSObject> array(JSArray::ArrayCreate(thread_, JSTaggedNumber(2)));
    PropertyDescriptor desc(thread_, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(30)));
    JSArray::DefineOwnProperty(thread_, array, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(0)), desc);

    PropertyDescriptor desc1(thread_, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(40)));
    JSArray::DefineOwnProperty(thread_, array, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(1)), desc1);

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(func.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));
    ecmaRuntimeCallInfo->SetCallArg(1, array.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Apply(ecmaRuntimeCallInfo.get());

    ASSERT_EQ(result.GetRawData(), JSTaggedValue(100).GetRawData());

    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")));
    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")));
}

// target.bind(thisArg)
TEST_F(BuiltinsFunctionTest, FunctionPrototypeBind)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    JSHandle<JSFunction> target = factory->NewJSFunction(env);
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(target),
                                JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("target")),
                                JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()));
    JSFunction::SetFunctionLength(thread_, target, JSTaggedValue(2));

    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(target.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Bind(ecmaRuntimeCallInfo.get());

    ASSERT_TRUE(result.IsECMAObject());

    JSHandle<JSBoundFunction> resultFunc(thread_, reinterpret_cast<TaggedObject *>(result.GetRawData()));
    // test BoundTarget
    ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
    // test BoundThis
    ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
    // test BoundArguments
    JSHandle<TaggedArray> array(thread_, resultFunc->GetBoundArguments());
    ASSERT_EQ(array->GetLength(), 0);
    // test name property
    auto globalConst = thread_->GlobalConstants();
    JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
    JSHandle<JSTaggedValue> resultFuncHandle(thread_, *resultFunc);
    JSHandle<EcmaString> resultName(JSObject::GetProperty(thread_, resultFuncHandle, nameKey).GetValue());
    JSHandle<EcmaString> boundTarget = factory->NewFromCanBeCompressString("bound target");
    ASSERT_EQ(resultName->Compare(*boundTarget), 0);
    // test length property
    JSHandle<JSTaggedValue> lengthKey = globalConst->GetHandledLengthString();
    JSHandle<JSTaggedValue> resultLength(JSObject::GetProperty(thread_, resultFuncHandle, lengthKey).GetValue());
    ASSERT_EQ(JSTaggedValue::ToNumber(thread_, resultLength).GetNumber(), 2.0);
}

// target.bind(thisArg, 123, "helloworld")
TEST_F(BuiltinsFunctionTest, FunctionPrototypeBind1)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    JSHandle<JSFunction> target = factory->NewJSFunction(env);
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(target),
                                JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("target1")),
                                JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()));
    JSFunction::SetFunctionLength(thread_, target, JSTaggedValue(5));

    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSHandle<EcmaString> str = factory->NewFromCanBeCompressString("helloworld");

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 10);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(target.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, thisArg.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(123)));
    ecmaRuntimeCallInfo->SetCallArg(2, str.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Bind(ecmaRuntimeCallInfo.get());

    ASSERT_TRUE(result.IsECMAObject());

    JSHandle<JSBoundFunction> resultFunc(thread_, reinterpret_cast<TaggedObject *>(result.GetRawData()));
    // test BoundTarget
    ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
    // test BoundThis
    ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
    // test BoundArguments
    JSHandle<TaggedArray> array(thread_, resultFunc->GetBoundArguments());
    ASSERT_EQ(array->GetLength(), 2);
    JSTaggedValue elem = array->Get(0);
    JSTaggedValue elem1 = array->Get(1);
    ASSERT_EQ(elem.GetRawData(), JSTaggedValue(123).GetRawData());

    ASSERT_EQ(elem1.GetRawData(), str.GetTaggedType());
    ASSERT_TRUE(elem1.IsString());
    // test name property
    auto globalConst = thread_->GlobalConstants();
    JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
    JSHandle<JSTaggedValue> resultFuncHandle(thread_, *resultFunc);
    JSHandle<EcmaString> resultName(JSObject::GetProperty(thread_, resultFuncHandle, nameKey).GetValue());
    JSHandle<EcmaString> rulerName = factory->NewFromCanBeCompressString("bound target1");
    ASSERT_EQ(resultName->Compare(*rulerName), 0);
    // test length property
    JSHandle<JSTaggedValue> lengthKey = globalConst->GetHandledLengthString();
    JSHandle<JSTaggedValue> resultLength(JSObject::GetProperty(thread_, resultFuncHandle, lengthKey).GetValue());
    // target.length is 5, (...args) length is 2
    ASSERT_EQ(JSTaggedValue::ToNumber(thread_, resultLength).GetNumber(), 3.0);
}

// target.bind(thisArg, 123, "helloworld") set target_name = EmptyString()
TEST_F(BuiltinsFunctionTest, FunctionPrototypeBind2)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    JSHandle<JSFunction> target = factory->NewJSFunction(env);
    PropertyDescriptor nameDesc(thread_, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(123)), false, false, true);
    JSTaggedValue::DefinePropertyOrThrow(thread_, JSHandle<JSTaggedValue>(target),
                                         thread_->GlobalConstants()->GetHandledNameString(), nameDesc);
    JSFunction::SetFunctionLength(thread_, target, JSTaggedValue(5));

    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSHandle<EcmaString> str = factory->NewFromCanBeCompressString("helloworld");

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 10);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(target.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(123)));
    ecmaRuntimeCallInfo->SetCallArg(2, str.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Bind(ecmaRuntimeCallInfo.get());

    ASSERT_TRUE(result.IsECMAObject());

    JSHandle<JSBoundFunction> resultFunc(thread_, reinterpret_cast<TaggedObject *>(result.GetRawData()));
    // test BoundTarget
    ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
    // test BoundThis
    ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
    // test BoundArguments
    JSHandle<TaggedArray> array(thread_, resultFunc->GetBoundArguments());
    ASSERT_EQ(array->GetLength(), 2);
    JSTaggedValue elem = array->Get(0);
    JSTaggedValue elem1 = array->Get(1);
    ASSERT_EQ(elem.GetRawData(), JSTaggedValue(123).GetRawData());

    ASSERT_EQ(elem1.GetRawData(), str.GetTaggedType());
    ASSERT_TRUE(elem1.IsString());
    // test name property
    auto globalConst = thread_->GlobalConstants();
    JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
    JSHandle<JSTaggedValue> resultFuncHandle(resultFunc);
    JSHandle<EcmaString> resultName(JSObject::GetProperty(thread_, resultFuncHandle, nameKey).GetValue());
    JSHandle<EcmaString> rulerName = factory->NewFromCanBeCompressString("bound ");
    ASSERT_EQ(resultName->Compare(*rulerName), 0);
    // test length property
    JSHandle<JSTaggedValue> lengthKey = globalConst->GetHandledLengthString();
    JSHandle<JSTaggedValue> resultLength(JSObject::GetProperty(thread_, resultFuncHandle, lengthKey).GetValue());
    // target.length is 5, (...args) length is 2
    ASSERT_EQ(JSTaggedValue::ToNumber(thread_, resultLength).GetNumber(), 3.0);
}

// func.call(thisArg)
TEST_F(BuiltinsFunctionTest, FunctionPrototypeCall)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    // ecma 19.2.3.3: func
    JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));

    // ecma 19.2.3.3: thisArg
    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(1)));
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(2)));

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(func.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Call(ecmaRuntimeCallInfo.get());

    ASSERT_EQ(result.GetRawData(), JSTaggedValue(3).GetRawData());

    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")));
    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")));
}

// func.call(thisArg, 123, 456, 789)
TEST_F(BuiltinsFunctionTest, FunctionPrototypeCall1)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();

    // ecma 19.2.3.3: func
    JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));

    // ecma 19.2.3.3: thisArg
    JSHandle<JSObject> thisArg(thread_, env->GetGlobalObject());
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(1)));
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(thisArg),
                          JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")),
                          JSHandle<JSTaggedValue>(thread_, JSTaggedValue(2)));

    // func thisArg ...args
    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 12);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(func.GetTaggedValue());
    ecmaRuntimeCallInfo->SetCallArg(0, (thisArg.GetTaggedValue()));
    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(123)));
    ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(456)));
    ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<int32_t>(789)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo.get());
    JSTaggedValue result = function::proto::Call(ecmaRuntimeCallInfo.get());

    ASSERT_EQ(result.GetRawData(), JSTaggedValue(1371).GetRawData());

    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_a")));
    JSObject::DeleteProperty(thread_, (thisArg),
                             JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("test_builtins_function_b")));
}

TEST_F(BuiltinsFunctionTest, FunctionPrototypeHasInstance)
{
    JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

    JSHandle<JSFunction> booleanCtor(env->GetBooleanFunction());

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue(*booleanCtor), 6);
    ecmaRuntimeCallInfo1->SetFunction(booleanCtor.GetTaggedValue());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(123)));

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo1.get());
    JSTaggedValue result = boolean::BooleanConstructor(ecmaRuntimeCallInfo1.get());
    TestHelper::TearDownFrame(thread_, prev);

    JSHandle<JSObject> booleanInstance(thread_, result);

    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(booleanCtor.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, booleanInstance.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo2.get());
    EXPECT_TRUE(function::proto::HasInstance(ecmaRuntimeCallInfo2.get()).GetRawData());
    TestHelper::TearDownFrame(thread_, prev);
}

// NOLINTEND(readability-magic-numbers)

}  // namespace ark::test
